#!/usr/bin/env ruby
# frozen_string_literal: true

REPL = true

require_relative "../loader"
require "timeout"

LOCATIONS = Location.where(visible: true).map { |l| [l, "#{l.provider} #{l.name} (#{l.display_name})"] }.to_h
REQUIRED_ENV_VARS = %w[HETZNER_USER HETZNER_PASSWORD HETZNER_SSH_PUBLIC_KEY HETZNER_SSH_PRIVATE_KEY].freeze

def get_input(msg, default = nil)
  prompt = "#{msg}#{" [default: #{default}]" unless default.nil?}: "
  input = ""

  while input.empty?
    print prompt
    input = gets.chomp
    input = default if input.empty? && !default.nil?
  end

  input
end

def select_option(msg, options, default = nil)
  puts "\n"
  options.each_with_index { |(key, name), index| puts "#{index + 1}. #{name}" }
  puts "\n"

  prompt = "#{msg}#{" [default: #{default}]" unless default.nil?}: "
  selected = nil

  while selected.nil?
    print prompt
    option = gets.chomp
    option = if option.empty?
      default
    elsif option.to_i < 1
      puts "Plese enter a number between 1-#{options.count}#{" or leave empty for default" unless default.nil?}"
    else
      option.to_i
    end

    selected = options.keys[option - 1] unless option.nil?
  end

  selected
end

unless REQUIRED_ENV_VARS.all? { Config.public_send(it.downcase) }
  puts "Please set the following variables in the .env file and re-run docker-compose up:"
  puts REQUIRED_ENV_VARS.join("\n")
  exit 1
end

hostname = get_input("Enter host IP address")
host_id = get_input("Enter host identifier", "")
location = select_option("Select provider and location", LOCATIONS, 1)

puts "\n\nCloudifying '#{hostname}' server for '#{LOCATIONS[location]}' \n\n"

if location.provider != HostProvider::HETZNER_PROVIDER_NAME
  puts "Currently only Hetzner is supported for this demo. Please use a Hetzner server for cloudification."
  exit 1
end

vm_host_ds = VmHost
  .where(id: Sshable.where(host: hostname).select(:id))
  .where(id: HostProvider.where(server_identifier: host_id).select(:id))
  .where(location_id: location.id)

strand = if (vmh = vm_host_ds.first)
  puts "Found existing cloudified server for '#{hostname}' with ID: #{vmh.id}"
  vmh.strand
else
  # Create a new strand for the cloudified server
  Prog::Vm::HostNexus.assemble(
    hostname,
    provider_name: location.provider,
    server_identifier: host_id,
    location_id: location.id,
    default_boot_images: ["ubuntu-noble"]
  )
end

begin
  Timeout.timeout(30 * 60) do
    puts "Waiting for server to be cloudified"
    previous_state = nil
    while (state = strand.reload.label) != "wait"
      if previous_state != state
        puts "#{Time.now} state: #{state}"
        previous_state = state
      end
      sleep 2
    end
  end
rescue Timeout::Error
  puts "\n\n"
  puts "Could not cloudify server in 30 minutes. Probably something went wrong."
  puts "Last state: #{strand.label}. Server ID for debug: #{strand.id}"
  puts "Please check your hostname/IP address and be sure that you added the correct public SSH key to your server."
  puts "You can ask for help on GitHub discussion page: https://github.com/ubicloud/ubicloud/discussions"
  exit 1
end

puts "\n\nYour server is cloudified now. You can create virtual machines at '#{LOCATIONS[location]}' in the cloud dashboard."
